﻿#region zh-CHS 2006 - 2007 DemoSoft 团队 | en 2006 - 2007 DemoSoft Team

//     NOTES
// ---------------
//
// This file is a part of the MMOSE(Massively Multiplayer Online Server Engine) for .NET.
//
//                              2006-2007 DemoSoft Team
//
//
// First Version : by H.Q.Cai - mailto:caihuanqing@hotmail.com

/***************************************************************************
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 ***************************************************************************/

#region zh-CHS 包含名字空间 | en Include namespace
using System;
using System.Threading;
using Microsoft.Win32.SafeHandles;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Runtime.ConstrainedExecution;
#endregion

namespace Demo.Mmose.Core.ThreadPool
{
    /// <summary>
    /// This class wraps a Win32 I/O Completion Port.
    /// </summary>
    internal sealed class IOCompletionPort : IDisposable
    {
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private SafeIOCompletionPortHandle m_hIOCP;
        #endregion

        #region zh-CHS 私有静态成员变量 | en Private Static Member Variables
        /// <summary>
        /// Internal helper members
        /// </summary>
        private static readonly SafeFileHandle s_InvalidFileHandle = new SafeFileHandle( unchecked( (IntPtr)( -1 ) ), true );
        /// <summary>
        /// Internal helper members
        /// </summary>
        private static readonly SafeIOCompletionPortHandle s_InvalidIOCompletionPortHandle = new SafeIOCompletionPortHandle( IntPtr.Zero, true );
        #endregion

        #region zh-CHS 构造和初始化和清理 | en Constructors and Initializers and Dispose
        /// <summary>
        /// IOCompletionPort constructor
        /// </summary>
        /// <param name="maxConcurrency">Maximum number of concurrent threads under a no IO blocking situation. If set to 0 will default to the number of processors on the computer</param>
        public IOCompletionPort( int maxConcurrency )
        {
            m_hIOCP = CreateIoCompletionPort( maxConcurrency );
        }

        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            Dispose( true );
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="disposing"></param>
        private void Dispose( bool disposing )
        {
            if ( disposing )
                m_hIOCP.Close();
        }
        #endregion

        #region zh-CHS 私有静态方法 | en Private Static Methods
        /// <summary>
        /// Creates a new IoCompletionPort
        /// </summary>
        /// <param name="numConcurrentThreads">Maximum number of concurrent threads under a no IO blocking situation. If set to 0 will default to the number of processors on the computer</param>
        /// <returns></returns>
        private static SafeIOCompletionPortHandle CreateIoCompletionPort( int numConcurrentThreads )
        {
            return CreateIoCompletionPort( s_InvalidFileHandle, s_InvalidIOCompletionPortHandle, UIntPtr.Zero, (UInt32)numConcurrentThreads );
        }
        #endregion

        #region zh-CHS 共有方法 | en Public Methods
        /// <summary>
        /// 
        /// </summary>
        /// <param name="callback"></param>
        public void PostStatus( WaitCallback callback )
        {
            PostStatus( callback, null );
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="waitCallback"></param>
        /// <param name="oState"></param>
        public void PostStatus( WaitCallback waitCallback, object oState )
        {
            if ( waitCallback == null )
                throw new ArgumentNullException( "waitCallback", "delegate must not be null" );

            GCHandle cbHandle = GCHandle.Alloc( waitCallback );

            GCHandle stateHandle = new GCHandle();
            if ( oState != null )
                stateHandle = GCHandle.Alloc( oState );

            bool bOk = PostQueuedCompletionStatus( m_hIOCP, 0, (IntPtr)cbHandle, ( oState == null ) ? IntPtr.Zero : (IntPtr)stateHandle );
            if ( bOk == false )
            {
                cbHandle.Free();

                if ( oState != null )
                    stateHandle.Free();

                throw new OverflowException( "Failed to post callback" );
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="iMilliseconds"></param>
        /// <param name="bTimedOut"></param>
        /// <param name="waitCallback"></param>
        /// <param name="oState"></param>
        [SuppressMessage( "Microsoft.Design", "CA1021:AvoidOutParameters" )]
        public void GetStatus( int iMilliseconds, out bool bTimedOut, out WaitCallback waitCallback, out object oState )
        {
            const uint WAIT_TIMEOUT = 258;
            // const UInt32 INFINITE = unchecked((UInt32) Timeout.Infinite);

            waitCallback = null;
            oState = null;

            IntPtr ptrCB = IntPtr.Zero;
            IntPtr ptrState = IntPtr.Zero;
            uint numBytesTransferred = 0;

            bool bOk = GetQueuedCompletionStatus( m_hIOCP, out numBytesTransferred, out ptrCB, out ptrState, (UInt32)iMilliseconds );
            int ioError = Marshal.GetLastWin32Error();
            
            bTimedOut = ( bOk == false && ( ptrState == IntPtr.Zero ) && ( ioError == WAIT_TIMEOUT ) );
            if ( bTimedOut )
                return;

            // Get the delegate to the callback method
            GCHandle cbHandle = (GCHandle)ptrCB;
            waitCallback = (WaitCallback)cbHandle.Target;
            cbHandle.Free();

            // Get the parameter to pass to the callback method
            if ( ptrState != IntPtr.Zero )
            {
                GCHandle stateHandle = (GCHandle)ptrState;
                oState = stateHandle.Target;
                stateHandle.Free();
            }
        }
        #endregion

        #region zh-CHS 引入DLL接口 | en DLL Import
        /// <summary>
        /// Interop methods
        /// </summary>
        /// <param name="hFile"></param>
        /// <param name="hExistingIOCP"></param>
        /// <param name="CompKey"></param>
        /// <param name="NumConcurrentThreads"></param>
        /// <returns></returns>
        [DllImport( "Kernel32", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true )]
        private static extern SafeIOCompletionPortHandle CreateIoCompletionPort( SafeFileHandle hFile, SafeIOCompletionPortHandle hExistingIOCP, UIntPtr CompKey, uint NumConcurrentThreads );

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hIOCP"></param>
        /// <param name="numBytesTransferred"></param>
        /// <param name="ptrCB"></param>
        /// <param name="ptrState"></param>
        /// <param name="uiMilliseconds"></param>
        /// <returns></returns>
        [DllImport( "Kernel32", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true )]
        [return: MarshalAs( UnmanagedType.Bool )]
        private static extern bool GetQueuedCompletionStatus( SafeIOCompletionPortHandle hIOCP, out uint numBytesTransferred, out IntPtr ptrCB, out IntPtr ptrState, uint uiMilliseconds );

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hIOCP"></param>
        /// <param name="numBytesTransferred"></param>
        /// <param name="ptrCB"></param>
        /// <param name="ptrState"></param>
        /// <returns></returns>
        [DllImport( "Kernel32", CallingConvention = CallingConvention.Winapi, ExactSpelling = true, SetLastError = true )]
        [return: MarshalAs( UnmanagedType.Bool )]
        private static extern bool PostQueuedCompletionStatus( SafeIOCompletionPortHandle hIOCP, uint numBytesTransferred, IntPtr ptrCB, IntPtr ptrState );
        #endregion
    }
}
#endregion